﻿//Visualizer 2D Graphics
namespace Diplom.Graphics.D2D
{
    using Diplom.NumericArrays;
    using SystemDraw = System.Drawing;
    using System;

    public static class D2DVisualizer
    {
        /// <summary>
        /// Convert world coordinates to molbert coordinates
        /// </summary>        
        public static SystemDraw.PointF Scalable(SystemDraw.PointF source, SystemDraw.RectangleF world, SystemDraw.RectangleF molbert)
        {
            SystemDraw.PointF target = new SystemDraw.PointF();            
            //ConvertX
            float minSource = world.X;
            float maxSource = world.X + world.Width;
            float minTarget = molbert.X;
            float maxTarget = molbert.X + molbert.Width;
            target.X = minTarget + (source.X - minSource) * (maxTarget - minTarget) / (maxSource - minSource);
            //ConvertY
            minSource = world.Y;
            maxSource = world.Y + world.Height;
            minTarget = molbert.Y;
            maxTarget = molbert.Y + molbert.Height;
            target.Y = maxTarget - (source.Y - minSource) * (maxTarget - minTarget) / (maxSource - minSource);
            return target;
        }

        /// <summary>
        /// Convert world coordinates to molbert coordinates
        /// </summary>        
        public static SystemDraw.PointF ScalableReverse(SystemDraw.PointF source, SystemDraw.RectangleF world, SystemDraw.RectangleF molbert)
        {
            SystemDraw.PointF target = new SystemDraw.PointF();
            //ConvertX
            float minSource = world.X;
            float maxSource = world.X + world.Width;
            float minTarget = molbert.X;
            float maxTarget = molbert.X + molbert.Width;
            target.X = minTarget + (source.X - minSource) * (maxTarget - minTarget) / (maxSource - minSource);
            //ConvertY
            minSource = world.Y;
            maxSource = world.Y + world.Height;
            minTarget = molbert.Y;
            maxTarget = molbert.Y + molbert.Height;
            target.Y = minTarget + (source.Y - minSource) * (maxTarget - minTarget) / (maxSource - minSource);
            return target;
        }

        /// <summary>
        /// Procedure drawing 2D graphics of numeric functions
        /// </summary>        
        public static void DrawGraphic(ref SystemDraw.Graphics molbert, ref Numeric1DArray graf, SystemDraw.RectangleF workRect, DrawStyle Style)
        {
            if (graf.Length <= 2) return;
            SystemDraw.RectangleF functionRect = new SystemDraw.RectangleF((float)graf.TimeMin, (float)graf.Min, (float)(graf.TimeMax - graf.TimeMin), (float)(graf.Max - graf.Min));
            if (Math.Abs(functionRect.Height) < 1e-5)
            {
                functionRect.Height = 1.0f;
                functionRect.Y -= 0.5f;
            }
            SystemDraw.PointF begin = Scalable(new SystemDraw.PointF((float)graf.TimeMin, (float)graf.Items[0]), functionRect, workRect);
            float delta = (float)((graf.TimeMax - graf.TimeMin) / graf.Length);
            for (int i = 1; i < graf.Length; i++)
            {
                SystemDraw.PointF current = Scalable(new SystemDraw.PointF((float)(graf.TimeMin + delta * i), (float)graf.Items[i]), functionRect, workRect);
                molbert.DrawLine(Style.DrawPen, begin, current);
                begin = current;
            }
        }

        public static void DrawSignature(ref SystemDraw.Graphics molbert, ref Numeric1DArray graf, SystemDraw.RectangleF workRect,DrawStyle Style,SystemDraw.Size size)
        {
            SystemDraw.RectangleF functionRect = new SystemDraw.RectangleF((float)graf.TimeMin, (float)graf.Min, (float)(graf.TimeMax - graf.TimeMin), (float)(graf.Max - graf.Min));
            if (Math.Abs(functionRect.Height) < 1e-5)
            {
                functionRect.Height = 1.0f;
                functionRect.Y -= 0.5f;
            }
            //Horizontal
            bool cel = true;
            if (graf.TimeMax - graf.TimeMin < graf.Length / 2) cel = false;
            float axis = 0;
            if (graf.Min > axis) axis = (float)graf.Min;
            if (graf.Max < axis) axis = (float)graf.Max;
            SystemDraw.PointF begin = Scalable(new SystemDraw.PointF((float)graf.TimeMin, axis), functionRect, workRect);
            float delta = (float)((graf.TimeMax - graf.TimeMin) / (size.Width - 1));
            for (int i = 1; i < size.Width; i++)
            {
                SystemDraw.PointF current = Scalable(new SystemDraw.PointF((float)(graf.TimeMin + delta * i), axis), functionRect, workRect);
                molbert.DrawLine(Style.DrawPen, begin, current);
                begin = current;
            }
            delta = (float)((graf.TimeMax - graf.TimeMin) / (size.Width - 1));
            for (int i = 0; i < size.Width; i++)
            {
                SystemDraw.PointF up = Scalable(new SystemDraw.PointF((float)(graf.TimeMin + i * delta), axis), functionRect, workRect);
                SystemDraw.PointF down = Scalable(new SystemDraw.PointF((float)(graf.TimeMin + i * delta), axis), functionRect, workRect);
                up.Y -= 2;
                down.Y += 2;
                molbert.DrawLine(Style.DrawPen, up, down);
                down.Y -= 18;
                down.X -=6;
                string num="";
                if (cel)
                    num = (graf.TimeMin + i * delta).ToString("f0");
                else
                    num = (graf.TimeMin + i * delta).ToString("f3");
                if (i>0 && i<size.Width-1)
                    molbert.DrawString(num, new SystemDraw.Font("Times New Roman", 7), Style.DrawBrush, down);
            }

            //Vertical
            axis = 0;
            if (graf.TimeMin > axis) axis = (float)graf.TimeMin;
            if (graf.TimeMax < axis) axis = (float)graf.TimeMax;
            begin = Scalable(new SystemDraw.PointF(axis,(float)graf.Min), functionRect, workRect);
            delta = (float)((graf.Max - graf.Min) / (size.Height - 1));
            for (int i = 1; i < size.Height; i++)
            {
                SystemDraw.PointF current = Scalable(new SystemDraw.PointF(axis, (float)graf.Min + i * delta), functionRect, workRect);
                molbert.DrawLine(Style.DrawPen, begin, current);
                begin = current;
            }
            delta = (float)((graf.Max - graf.Min) / (size.Height - 1));
            
            for (int i = 0; i < size.Height; i++)
            {
                SystemDraw.PointF left = Scalable(new SystemDraw.PointF(axis, (float)(graf.Min + i * delta)), functionRect, workRect);
                SystemDraw.PointF right = Scalable(new SystemDraw.PointF(axis, (float)(graf.Min + i * delta)), functionRect, workRect);
                left.X -= 2;
                right.X += 2;
                molbert.DrawLine(Style.DrawPen, left, right);
                right.Y -= 6;
                right.X -= 40;
                string num = (graf.Min + i * delta).ToString("f2");
                while (num.Length < 7) num = " " + num;
                
                molbert.DrawString(num, new SystemDraw.Font("Times New Roman", 7), Style.DrawBrush, right);

            }

        }

        public static void DrawSignatureTwoPowers(ref SystemDraw.Graphics molbert, ref Numeric1DArray graf, SystemDraw.RectangleF workRect, DrawStyle Style, SystemDraw.Size size)
        {
            SystemDraw.RectangleF functionRect = new SystemDraw.RectangleF((float)graf.TimeMin, (float)graf.Min, (float)(graf.TimeMax - graf.TimeMin), (float)(graf.Max - graf.Min));
            if (Math.Abs(functionRect.Height) < 1e-5)
            {
                functionRect.Height = 1.0f;
                functionRect.Y -= 0.5f;
            }
            //Horizontal
            float axis = 0;
            if (graf.Min > axis) axis = (float)graf.Min;
            if (graf.Max < axis) axis = (float)graf.Max;
            SystemDraw.PointF begin = Scalable(new SystemDraw.PointF((float)graf.TimeMin, axis), functionRect, workRect);
            float delta = (float)((graf.TimeMax - graf.TimeMin) / (size.Width - 1));
            for (int i = 1; i < size.Width; i++)
            {
                SystemDraw.PointF current = Scalable(new SystemDraw.PointF((float)(graf.TimeMin + delta * i), axis), functionRect, workRect);
                molbert.DrawLine(Style.DrawPen, begin, current);
                begin = current;
            }
            delta = (float)((graf.TimeMax - graf.TimeMin) / (size.Width - 1));
            for (int i = 0; i < size.Width; i++)
            {
                SystemDraw.PointF up = Scalable(new SystemDraw.PointF((float)(graf.TimeMin + i * delta), axis), functionRect, workRect);
                SystemDraw.PointF down = Scalable(new SystemDraw.PointF((float)(graf.TimeMin + i * delta), axis), functionRect, workRect);
                up.Y -= 2;
                down.Y += 2;
                molbert.DrawLine(Style.DrawPen, up, down);
                down.Y -= 18;
                down.X -= 6;
                string num = (graf.TimeMin + i * delta).ToString("f0");
                molbert.DrawString(num, new SystemDraw.Font("Times New Roman", 7), Style.DrawBrush, down);
            }

            //Vertical
            axis = 0;
            if (graf.TimeMin > axis) axis = (float)graf.TimeMin;
            if (graf.TimeMax < axis) axis = (float)graf.TimeMax;
            begin = Scalable(new SystemDraw.PointF(axis, (float)graf.Min), functionRect, workRect);
            delta = (float)((graf.Max - graf.Min) / (size.Height - 1));
            for (int i = 1; i < size.Height; i++)
            {
                SystemDraw.PointF current = Scalable(new SystemDraw.PointF(axis, (float)graf.Min + i * delta), functionRect, workRect);
                molbert.DrawLine(Style.DrawPen, begin, current);
                begin = current;
            }
            delta = (float)((graf.Max - graf.Min) / (size.Height - 1));

            for (int i = 0; i < size.Height; i++)
            {
                SystemDraw.PointF left = Scalable(new SystemDraw.PointF(axis, (float)(graf.Min + i * delta)), functionRect, workRect);
                SystemDraw.PointF right = Scalable(new SystemDraw.PointF(axis, (float)(graf.Min + i * delta)), functionRect, workRect);
                left.X -= 2;
                right.X += 2;
                molbert.DrawLine(Style.DrawPen, left, right);
                right.Y -= 6;
                right.X -= 40;
                string num = (Math.Pow(2.0,graf.Min + i * delta)).ToString("f0");
                while (num.Length < 7) num = " " + num;

                molbert.DrawString(num, new SystemDraw.Font("Times New Roman", 7), Style.DrawBrush, right);

            }

        }
    }
}
